package cos.android.tim.element;

import java.util.Vector;

import android.graphics.Bitmap;
import android.graphics.Rect;
import cos.android.tim.utils.Factory;
import cos.android.tim.utils.Point;

public abstract class Element implements Cloneable {

	private Bitmap sprite;
	private Bitmap colisionSprite;
	private Bitmap miniature;

	private String name;
	private Point origin;
	private String kind;
	private Factory father;

	private int height;
	private int width;

	private Rect rect;

	private DinamicElement dinamicElement;
	private Activable activable;
	private Chainable chainable;
	private Ropeable ropeable;
	private Circle circle;
	private Polygon polygon;
	private Moveable moveable;
	private Electric electric;
	private ElectricGenerator electricGenerator;

	public Element(Bitmap sprite, Bitmap colisionSprite, Bitmap miniSprite,
			int xPos, int yPos, String kind) {
		super();
		name = "";
		this.sprite = sprite;
		origin = new Point(xPos, yPos);
		this.height = sprite.getHeight();
		this.width = sprite.getWidth();
		this.rect = new Rect(0, 0, getWidth(), getHeight());
		this.kind = kind;
		this.colisionSprite = colisionSprite;
		this.miniature = miniSprite;
		father = null;
		moveable = null;
		dinamicElement = null;
		activable = null;
		chainable = null;
		ropeable = null;
		circle = null;
		polygon = null;
		electric = null;
		electricGenerator = null;

	}

	public Point getOrigin() {
		return origin;
	}

	public float getxPos() {
		return origin.getxPos();
	}

	public void setxPos(float xPos) {

		origin.setxPos(xPos);
	}

	public float getyPos() {
		return origin.getyPos();
	}

	public void setyPos(float yPos) {
		origin.setyPos(yPos);
	}

	public Bitmap getSprite() {
		return sprite;
	}

	public void setSprite(Bitmap sprite) {
		this.sprite = sprite;
	}

	public Bitmap getColisionSprite() {
		return colisionSprite;
	}

	public void setColisionSprite(Bitmap colisionSprite) {
		this.colisionSprite = colisionSprite;
	}

	public Bitmap getMiniature() {
		return miniature;
	}

	public void setMiniature(Bitmap miniature) {
		this.miniature = miniature;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public Rect getRect() {
		return rect;
	}

	public void setRect(Rect rect) {
		this.rect = rect;
	}

	public void setKind(String kind) {
		this.kind = kind;
	}

	public String getKind() {
		return kind;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean isDinamicElement() {
		return (dinamicElement != null);
	}

	public void setDinamicElement(DinamicElement dinamicElement) {
		this.dinamicElement = dinamicElement;
	}

	public void setActivable(Activable activable) {
		this.activable = activable;
	}

	public boolean isActivable() {
		return (activable != null);
	}

	public boolean isElectricGenerator() {
		return (electricGenerator != null);
	}

	public void setElectricGenerator(ElectricGenerator electricGenerator) {
		this.electricGenerator = electricGenerator;
	}

	public void setChainable(Chainable chainable) {
		this.chainable = chainable;
	}

	public boolean isChainable() {
		return (chainable != null);
	}

	public boolean isMoveable() {
		return (moveable != null);
	}

	public void setMoveable(Moveable moveable) {
		this.moveable = moveable;
	}

	public boolean isRopeable() {
		return (ropeable != null);
	}

	public void setRopeable(Ropeable ropeable) {
		this.ropeable = ropeable;
	}

	public void setElectric(Electric electric) {
		this.electric = electric;
	}

	public boolean isElectric() {
		return (electric != null);
	}

	public boolean isPolygon() {
		return (polygon != null);
	}

	public void setPolygon(Polygon polygon) {
		this.polygon = polygon;
	}

	public boolean isCircle() {
		return (circle != null);
	}

	public void setCircle(Circle circle) {
		this.circle = circle;
	}

	public boolean checkCollision(Element element) {

		Rect dest = new Rect(Math.round(getxPos()), Math.round(getyPos()),
				Math.round(getxPos() + getWidth()), Math.round(getyPos()
						+ getHeight()));

		Rect dest2 = new Rect(Math.round(element.getxPos()), Math.round(element
				.getyPos()),
				Math.round(element.getxPos() + element.getWidth()),
				Math.round(element.getyPos() + element.getHeight()));

		return (dest.intersect(dest2));

	}

	public boolean isTouched(float touchX, float touchY) {

		if ((getxPos() < touchX) && (getxPos() + getWidth() > touchX)
				&& (getyPos() < touchY) && (getyPos() + getHeight() > touchY)) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public Element clone() {

		Element clone;
		try {
			clone = (Element) super.clone();
			clone.origin = new Point(0, 0);
			clone.setFather(getFather());
			clone.setxPos(getxPos());
			clone.setyPos(getyPos());
			if (dinamicElement != null) {
				clone.setDinamicElement((DinamicElement) dinamicElement.clone());
			}
			if (circle != null) {
				clone.setCircle(new Circle());
			}
		} catch (CloneNotSupportedException e) {
			System.out.println("Cloning not allowed.");
			return this;
		}
		return clone;
	}

	public boolean isName(String name) {

		if (this.name == null) {
			return false;
		} else {
			return this.name.equals(name);
		}
	}

	public boolean isRope() {
		return ropeable.isLinked();
	}

	public boolean isLinked() {
		return (ropeable.isLinked());
	}

	public Point extremePoint() {
		return ropeable.getExtremePoint(origin);
	}

	public float getoX() {
		if (dinamicElement != null) {
			return dinamicElement.getoX();
		}
		return 0;
	}

	public float getoY() {
		if (dinamicElement != null) {
			return dinamicElement.getoY();
		}
		return 0;
	}

	public Element getLastHitted() {
		if (dinamicElement != null) {
			return dinamicElement.getLastHitted();
		}
		return null;
	}

	public void setLastHitted(Element element) {
		if (dinamicElement != null) {
			dinamicElement.setLastHitted(element);
		}
	}

	public void applySpeed(float ox, float oy) {
		if (dinamicElement != null) {
			if ((getKind().equals("Rampa")) || (getKind().equals("Rampa2"))
					|| (getKind().equals("HorizontalWall"))
					|| (getKind().equals("VerticalWall"))) {
				System.out.println("Se movio el muro!!" + getKind());
			}
			dinamicElement.applySpeed(ox, oy);
		}
	}

	public float getSpeed() {
		if (dinamicElement != null) {
			return dinamicElement.getSpeed();
		} else {
			return 0f;
		}
	}

	public void update(float elapsed) {
		if (dinamicElement != null) {
			dinamicElement.update(this, elapsed);
		}
	}

	public Vector<Point> getAristas() {
		if (polygon != null) {
			return polygon.getRealAristas(origin);
		} else {
			return circle.getAristas(origin, height);
		}
	}

	public float getCenterX() {
		if (isCircle()) {
			return circle.getCenterX(origin, height);
		} else {
			return (getxPos() + getWidth() / 2);
		}
	}

	public float getCenterY() {
		if (isCircle()) {
			return circle.getCenterY(origin, height);
		} else {
			return (getyPos() + getHeight() / 2);
		}
	}

	public float getRadius() {
		return circle.getRadius(getHeight());
	}

	public void setOn(boolean on) {
		electric.setOn(on);
	}

	public boolean isOn() {
		if (electric != null) {
			return electric.isOn();
		}
		return false;
	}

	public void action() {

		if (getKind().equals("Batery") && !isActive()) {
			activable.setActive(true);
			setOn(true);
		} else if (getKind().equals("JumpBox") && !isOn()) {
			setOn(true);
			System.out.println("Activado");
		} else if (getKind().equals("Punch") && !isActive() && !isOn()) {
			activable.setActive(true);
			setOn(true);
		} else if (getKind().equals("Radio") && !isActive()) {
			activable.setActive(true);
		}

	}

	public float getFlexibility() {
		if (dinamicElement != null) {
			return dinamicElement.getFlexibility();

		}
		return 0;
	}

	public boolean collition(Point point) {
		if (isCircle()) {
			if (circle.colition(origin, point, height)) {
				return true;
			} else {
				return false;
			}
		} else {
			if (polygon.collition(origin, point)) {
				return true;
			} else {
				return false;
			}
		}
	}

	public Factory getFather() {
		return father;
	}

	public void setFather(Factory father) {
		this.father = father;
	}

	public void dispose() {
		if (father != null) {
			father.setNumber(father.getNumber() + 1);
		}
	}

	public void resetX() {
		if (dinamicElement != null) {
			dinamicElement.resetX();
		}
	}

	public void resetY() {
		if (dinamicElement != null) {
			dinamicElement.resetY();
		}
	}

	public void reset() {
		if (dinamicElement != null) {
			dinamicElement.reset();
		}
	}

	public Point collition(Element element) {
		if (isCircle()) {
			return circle.colition(origin, element, height);
		} else {
			return polygon.collition(origin, element);
		}
	}

	public boolean isCorrectPosition() {
		if (moveable != null) {
			return moveable.isCorrectPosition();
		}
		return true;
	}

	public void setCorrectPosition(boolean correct) {
		moveable.setCorrectPosition(correct);
	}

	public void normalizePosition(int block) {

		float divx = Math.round(origin.getxPos() % block);
		float divy = Math.round(origin.getyPos() % block);

		if (divx <= 2) {
			origin.setxPos((Math.round(origin.getxPos() - divx) / block)
					* block);

		} else {
			origin.setxPos((Math.round(origin.getxPos() + block - divx) / block)
					* block);
		}
		if (divy <= 2) {
			origin.setyPos((Math.round(origin.getyPos() - divy) / block)
					* block);

		} else {
			origin.setyPos((Math.round(origin.getyPos() + block - divy) / block)
					* block);
		}
	}

	public boolean isActive() {
		if (activable != null) {
			return activable.isActive();
		}
		return false;
	}

	public void setActive(boolean active) {
		if (activable != null) {
			activable.setActive(active);
		}
	}

	public void refreshAristas() {

	}

	@Override
	public String toString() {
		return (this.kind + " " + origin.toString());
	}

	public void reactToColition(Point contactPoint) {

		if (isCircle()) {
			float dx = circle.getCenterX(origin, height)
					- contactPoint.getxPos();
			float dy = circle.getCenterY(origin, height)
					- contactPoint.getyPos();

			float dxb = Math.abs(circle.getCenterX(origin, height)
					- contactPoint.getxPos());
			float dyb = Math.abs(circle.getCenterY(origin, height)
					- contactPoint.getyPos());

			float propY = (dyb / (dxb + dyb));
			float propX = 1 - propY;

			float previousSpeed = getSpeed();
			reset();
			System.out.println("contact: " + contactPoint.toString());
			System.out.println("center: " + circle.getCenterX(origin, height)
					+ " " + circle.getCenterY(origin, height));
			System.out.println("x: " + propX + " " + Math.signum(dx));
			System.out.println("y: " + propY + " " + Math.signum(dy));
			System.out.println("");
			applySpeed(
					previousSpeed * propX * getFlexibility() * Math.signum(dx),
					Math.signum(dy) * previousSpeed * propY * getFlexibility());

		}
	}
}
